use std::{collections::HashMap, path::{Path, PathBuf}};

use normalize_path::NormalizePath;
use rfd::FileDialog;
use serde::{Deserialize, Serialize};

use crate::{exporter::generate_export_graph_data, graph::{self, value::Value, Graph}};

const PROJ_EXTENSION:&str = "bproj";


#[derive(Clone, Copy, Hash, PartialEq, Eq)]
enum ModalFlag {
    Save,
    AppConfig,
}

struct AllModalFlag {
    flags: Vec<(ModalFlag, Option<HashMap<String, String>>)>,
    opened: Vec<(ModalFlag, Option<HashMap<String, String>>)>,
}

impl AllModalFlag {
    fn new() -> Self {
        Self {
            flags: Vec::new(),
            opened: Vec::new(),
        }
    }

    fn insert(&mut self, flag: ModalFlag, data: Option<HashMap<String, String>>) {
        self.flags.push((flag, data));
    }

    fn open(&mut self, flag:ModalFlag)-> bool {
        if self.opened.iter().any(|(f, _)| *f == flag) {
            return false;
        }

        //从flags中找到对应的flag移除并加入opened
        if let Some(index) = self.flags.iter().position(|(f, _)| *f == flag) {
            let removed = self.flags.remove(index);
            self.opened.push(removed);
            return true;
        }

        return false;
    }

    fn get_open_data(&self, flag:ModalFlag)-> Option<&HashMap<String, String>> {
        self.opened.iter().find_map(|(f, data)| if *f == flag { data.as_ref() } else { None })
    }

    fn close(&mut self, flag:ModalFlag){
        self.opened.retain(|(f, _)| *f != flag);
    }

}

#[derive(Serialize, Deserialize, Clone)]
pub struct AppConfig {
    workdir: Option<String>,
    export_dir: Option<String>,
}

impl Default for AppConfig {
    fn default() -> Self {
        Self {
            workdir: None,
            export_dir: None,
        }
    }
}

pub struct App {
    pub graph: graph::Graph,//(打开的)行为树节点数据
    pub app_config: AppConfig,
    dirty:bool,
    add_const_name: String,
    add_const_value: Value,
    add_custom_data_name: String,
    add_custom_data_value: Value,
    model_flags:AllModalFlag,
    temp_datas:HashMap<String, String>,
    project_dir: PathBuf,
    current_file: Option<String>,
    confirm_close: bool,
    graph_data: Option<crate::data::GraphData>,
}

impl App {
    pub fn new() -> Self {
        let project_dir = directories::ProjectDirs::from("cn", "waidais", "behavioreditor").unwrap().data_dir().to_path_buf();
        if let Err(e) = std::fs::create_dir_all(&project_dir) {
            eprintln!("无法创建配置目录: {:?}", e);
        }
        let mut this = Self {
            graph: graph::Graph::new(),
            app_config: AppConfig::default(),
            dirty: false,
            add_const_name: String::new(),
            add_const_value: Value::I32(0),
            add_custom_data_name: String::new(),
            add_custom_data_value: Value::I32(0),
            model_flags: AllModalFlag::new(),
            temp_datas: HashMap::new(),
            project_dir,
            current_file: None,
            confirm_close: false,
            graph_data: None,
        };

        this.load_app_config();

        this.graph.init(this.app_config.workdir.clone().unwrap_or_default());

        this
    }
}

impl App {
    pub fn set_graph_data(&mut self, graph_data: crate::data::GraphData) {
        self.graph_data = Some(graph_data.clone());
        self.graph.set_graph_data(graph_data);
    }

    pub fn clear_dirty(&mut self) {
        self.dirty = false;
        self.graph.clear_dirty();
    }
}

impl App {
    fn check_exit(&mut self, ctx: &egui::Context) {
        if self.dirty {
            if ctx.input(|i| i.viewport().close_requested()) {
                if self.confirm_close {
                    return;
                }
                let mut params = HashMap::new();
                params.insert("Action".to_owned(), "Close".to_owned());
                self.model_flags.insert(ModalFlag::Save, Some(params));
                ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);
            }
        }
    }

    fn handle_shortcut(&mut self, ctx:&egui::Context){
        if ctx.input(|i| i.modifiers.ctrl) {
            if ctx.input(|i|i.modifiers.shift){
                if ctx.input(|i| i.key_pressed(egui::Key::S)) {
                    self.save_to();
                } else if ctx.input(|i| i.key_pressed(egui::Key::E)){
                    self.export_to();
                }
            } else {
                if ctx.input(|i| i.key_pressed(egui::Key::S)) {
                    self.save();
                } else if ctx.input(|i| i.key_pressed(egui::Key::O)){
                    self.open();
                } else if ctx.input(|i| i.key_pressed(egui::Key::N)){
                    self.new_project();
                } else if ctx.input(|i| i.key_pressed(egui::Key::E)){
                    self.export();
                } else if ctx.input(|i| i.key_pressed(egui::Key::I)){
                    self.import_graph();
                }
            }
        }
    }
}

impl eframe::App for App {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        self.check_exit(ctx);
        self.handle_shortcut(ctx);

        egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
            egui::menu::bar(ui, |ui| {
                self.draw_top_menu(ctx, ui);
            });
        });

        egui::CentralPanel::default().show(ctx, |ui|{
            self.graph.show(ui);
            self.dirty = self.dirty || self.graph.viewer.is_dirty();
            if self.dirty {
                ctx.send_viewport_cmd(egui::ViewportCommand::Title("behavior editor *".to_owned()));//这里之后改成文件名，先暂时这样
            } else {
                ctx.send_viewport_cmd(egui::ViewportCommand::Title("behavior editor".to_owned()));
            }
        });

        egui::SidePanel::left("left_panel").show(ctx, |ui| {
            self.draw_left_panel(ui);
        });

        self.draw_modals(ctx);
    }
}

impl App {
    fn save_app_config(&self) {
        let app_config_file = self.project_dir.join("app_config.json");
        if let Ok(mut file_writer) = std::fs::File::create(&app_config_file) {
            if let Ok(json) = serde_json::to_string(&self.app_config) {
                if let Err(e) = std::io::Write::write_all(&mut file_writer, json.as_bytes()) {
                    eprintln!("保存应用配置失败: {:?}", e);
                }
            } else {
                eprintln!("保存应用配置失败：无法序列化配置为JSON");
            }
        } else {
            eprintln!("保存应用配置失败：无法创建配置文件: {:?}", app_config_file);
        }
    }
    

    fn load_app_config(&mut self) {
        let app_config_file = self.project_dir.join("app_config.json");
        if let Ok(file_reader) = std::fs::File::open(&app_config_file) {
            if let Ok(app_config) = serde_json::from_reader(file_reader) {
                self.app_config = app_config;
            }
        }
    }
}

impl App {
    fn draw_modals(&mut self, ctx: &egui::Context) {
        let save_model = egui_modal::Modal::new(ctx, "save_dialog");
        save_model.show(|ui|{
            save_model.title(ui, "确认");
            save_model.frame(ui, |ui|{
                save_model.body(ui, "当前行为树已经修改，是否保存？");
            });
            save_model.buttons(ui, |ui|{
                if save_model.suggested_button(ui, "保存").clicked() {
                    self.save();
                    let params = self.model_flags.get_open_data(ModalFlag::Save);
                    if let Some(params) = params {
                        if let Some(action) = params.get("Action") {
                            match action.as_str() {
                                "New" => {
                                    self.new_project();
                                }
                                "Open" => {
                                    self.open();
                                }
                                "Close" => {
                                    self.confirm_close = true;
                                    ctx.send_viewport_cmd(egui::ViewportCommand::Close);
                                }
                                _ => {}
                            }
                        }
                    }
                    self.model_flags.close(ModalFlag::Save);
                }
                if save_model.caution_button(ui, "不保存").clicked() {
                    let params = self.model_flags.get_open_data(ModalFlag::Save);
                    if let Some(params) = params {
                        if let Some(action) = params.get("Action") {
                            match action.as_str() {
                                "New" => {
                                    self.new_project();
                                }
                                "Open" => {
                                    self.open();
                                }
                                "Close" => {
                                    self.confirm_close = true;
                                    ctx.send_viewport_cmd(egui::ViewportCommand::Close);
                                }
                                _ => {}
                            }
                        }
                    }
                    self.model_flags.close(ModalFlag::Save);
                }
                if save_model.button(ui, "取消").clicked() {
                    self.model_flags.close(ModalFlag::Save);
                }
            });
        });

        let app_config_model = egui_modal::Modal::new(ctx, "app_config_dialog");
        app_config_model.show(|ui|{
            app_config_model.title(ui, "应用配置");
            app_config_model.frame(ui, |ui|{
                ui.horizontal(|ui|{
                    ui.label("工作目录:");
                    let mut workdir = self.temp_datas.get("workdir").cloned().unwrap_or_default();
                    if ui.text_edit_singleline(&mut workdir).changed() {
                        self.temp_datas.insert("workdir".to_owned(), workdir);
                    }
                    if ui.button("...").clicked() {
                        let file_dialog = FileDialog::new().set_directory(self.temp_datas.get("workdir").cloned().unwrap_or_default());
                        if let Some(workdir) = file_dialog.pick_folder() {
                            if let Some(workdir) = workdir.to_str() {
                                self.temp_datas.insert("workdir".to_owned(), workdir.to_owned());
                            }
                        }
                    }
                });
                ui.horizontal(|ui|{
                    ui.label("导出目录:");
                    let mut export_dir = self.temp_datas.get("export_dir").cloned().unwrap_or_default();
                    if ui.text_edit_singleline(&mut export_dir).changed() {
                        self.temp_datas.insert("export_dir".to_owned(), export_dir);
                    }
                    if ui.button("...").clicked() {
                        let file_dialog = FileDialog::new().set_directory(self.temp_datas.get("export_dir").cloned().unwrap_or_default());
                        if let Some(export_dir) = file_dialog.pick_folder() {
                            if let Some(export_dir) = export_dir.to_str() {
                                self.temp_datas.insert("export_dir".to_owned(), export_dir.to_owned());
                            }
                        }
                    }
                });
            });
            app_config_model.buttons(ui, |ui|{
                if app_config_model.button(ui, "确定").clicked() {
                    self.app_config.workdir = self.temp_datas.get("workdir").cloned();
                    self.app_config.export_dir = self.temp_datas.get("export_dir").cloned();
                    self.save_app_config();
                    self.model_flags.close(ModalFlag::AppConfig);
                }

                if app_config_model.button(ui, "取消").changed() {
                    self.temp_datas.remove("workdir");
                    self.temp_datas.remove("export_dir");
                    self.model_flags.close(ModalFlag::AppConfig);
                }
            });
        });

        if self.model_flags.open(ModalFlag::Save) {
            save_model.open();
        }

        if self.model_flags.open(ModalFlag::AppConfig) {
            self.temp_datas.insert("workdir".to_owned(), self.app_config.workdir.clone().unwrap_or_default());
            self.temp_datas.insert("export_dir".to_owned(), self.app_config.export_dir.clone().unwrap_or_default());
            app_config_model.open();
        }
    }
}

fn draw_type_selector(ui: &mut egui::Ui, value: &mut Value, id: &str) {
    let current_text = value.get_type_string();
    let all_base_types = Value::get_all_base_types();
    let mut select_index = all_base_types.iter().position(|t| t.is_same_type(value)).unwrap_or(0);
    egui::ComboBox::from_id_salt(id).selected_text(current_text).show_ui(ui, |ui|{
        for (i, t) in all_base_types.iter().enumerate() {
            ui.selectable_value(&mut select_index, i, t.get_type_string());
        }
        value.clone_from(&all_base_types[select_index]);
    });
}

impl App {
    fn draw_left_panel(&mut self, ui: &mut egui::Ui) {
        //向下滑动
        egui::ScrollArea::vertical().show(ui, |ui|{
            egui::CollapsingHeader::new("常量").default_open(true).show(ui, |ui|{
                //添加常量数据
                ui.horizontal(|ui|{
                    ui.label("名称:");
                    ui.text_edit_singleline(&mut self.add_const_name);
                    ui.label("类型:");
                    draw_type_selector(ui, &mut self.add_const_value, "const_type");
                    if ui.button("添加").clicked() && !self.add_const_name.is_empty() {
                        self.graph.add_constant(self.add_const_name.clone(), self.add_const_value.clone());
                        self.add_const_name.clear();
                        self.add_const_value = Value::I32(0);
                        self.dirty = true;
                    }
                });
                //显示常量数据
                let const_datas = self.graph.constants.iter_mut().collect::<Vec<_>>();
                let mut delete_name: Option<String> = None;
                for (name, value) in const_datas {
                    ui.horizontal(|ui|{
                        ui.label(name);
                        ui.label(value.get_type_string());
                        ui.label("值:");
                        if show_value(ui, value) {
                            self.dirty = true;
                        }
                        if ui.button("删除").clicked() {
                            delete_name = Some(name.clone());
                        }
                    });
                }

                if let Some(name) = delete_name {
                    self.graph.remove_constant(&name);
                    self.dirty = true;
                }
            });

            egui::CollapsingHeader::new("自定义数据").default_open(true).show(ui, |ui|{
                //添加自定义数据
                ui.horizontal(|ui|{
                    ui.label("名称:");
                    ui.text_edit_singleline(&mut self.add_custom_data_name);
                    ui.label("类型:");
                    draw_type_selector(ui, &mut self.add_custom_data_value, "custom_data_type");
                    if ui.button("添加").clicked() && !self.add_custom_data_name.is_empty() {
                        self.graph.add_custom_data(self.add_custom_data_name.clone(), self.add_custom_data_value.clone());
                        self.add_custom_data_name.clear();
                        self.add_custom_data_value = Value::I32(0);
                        self.dirty = true;
                    }                    
                });

                //显示自定义数据
                let custom_datas = self.graph.custom_datas.iter_mut().collect::<Vec<_>>();
                let mut delete_name: Option<String> = None;
                for (name, value) in custom_datas {
                    ui.horizontal(|ui|{
                        ui.label(name);
                        ui.label(value.get_type_string());
                        ui.label("值:");
                        if show_value(ui, value) {
                            self.dirty = true;
                        }
                        if ui.button("删除").clicked() {
                            delete_name = Some(name.clone());
                        }
                    });
                }
                if let Some(name) = delete_name {
                    self.graph.remove_custom_data(&name);
                    self.dirty = true;
                }
            });
        });
    }
}

fn show_value(ui: &mut egui::Ui, value: &mut Value) -> bool {
    let mut changed = false;
    match value {
        Value::I64(v) => {
            let drag_value = egui::DragValue::new(v).speed(1);
            if ui.add(drag_value).changed() {
                changed = true;
            }
        }
        Value::I32(v) => {
            let drag_value = egui::DragValue::new(v).speed(1);
            if ui.add(drag_value).changed() {
                changed = true;
            }
        }
        Value::F32(v) => {
            let drag_value = egui::DragValue::new(v).speed(0.1);
            if ui.add(drag_value).changed() {
                changed = true;
            }
        }
        Value::F64(v) => {
            let drag_value = egui::DragValue::new(v).speed(0.1);
            if ui.add(drag_value).changed() {
                changed = true;
            }
        }
        Value::Bool(v) => {
            if ui.checkbox(v, "bool").changed() {
                changed = true;
            }
        }
        Value::String(v) => {
            if ui.text_edit_singleline(v).changed() {
                changed = true;
            }
        }
        _ => {
            ui.label("暂不支持");
        }
    }

    changed
}

impl App {
    fn draw_top_menu(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui) {
        ui.menu_button("文件", |ui|{
            if ui.button("新建(N)").on_hover_text("Ctrl + N").clicked() {
                if self.dirty {
                    let mut params = HashMap::new();
                    params.insert("Action".to_owned(), "New".to_owned());
                    self.model_flags.insert(ModalFlag::Save, Some(params));
                } else {
                    self.new_project();
                }
                ui.close_menu();
            }
            if ui.button("打开(O)").on_hover_text("Ctrl + O").clicked() {
                if self.dirty {
                    let mut params = HashMap::new();
                    params.insert("Action".to_owned(), "Open".to_owned());
                    self.model_flags.insert(ModalFlag::Save, Some(params));
                } else {
                    self.open();
                }
                ui.close_menu();
            }
            if ui.button("保存(S)").on_hover_text("Ctrl + S").clicked() {
                //TODO:保存文件
                self.save();
                self.clear_dirty();
                ui.close_menu();
            }

            if ui.button("另存为(^S)").on_hover_text("Ctrl + Shift + S").clicked() {
                //TODO:另存为文件
                self.save_to();
                self.clear_dirty();
                ui.close_menu();
            }

            if ui.button("导出(E)").on_hover_text("Ctrl + E").clicked() {
                self.export();
                ui.close_menu();
            }

            if ui.button("导出到(^E)").on_hover_text("Ctrl + Shift + E").clicked() {
                self.export_to();
                ui.close_menu();
            }

            if ui.button("应用配置").clicked() {
                self.model_flags.insert(ModalFlag::AppConfig, None);
                ui.close_menu();
            }
        });

        ui.menu_button("引用", |ui|{
            if ui.button("添加引用(I)").on_hover_text("Ctrl + I").clicked() {
                self.import_graph();
                ui.close_menu();
            }

            ui.menu_button("删除引用", |ui|{
                let all_include_graphs = self.graph.include_graphs.iter().map(|p| p.to_owned()).collect::<Vec<_>>();
                for name in all_include_graphs.iter() {
                    let button = egui::Button::new(name).wrap_mode(egui::TextWrapMode::Extend);
                    if ui.add(button).clicked() {
                        self.remove_include_graph(&name);
                    }
                }
            });
        });
    }
}

impl App {
    fn new_project(&mut self) {
        self.graph = graph::Graph::default();
        self.current_file = None;
        self.clear_dirty();
    }

    fn open(&mut self) {
        let workdir = self.app_config.workdir.clone().unwrap_or_default();
        let file_dialog = FileDialog::new().set_directory(workdir.clone()).add_filter("行为树", &[PROJ_EXTENSION]);
        if let Some(file) = file_dialog.pick_file() {
            match Graph::load_from_path(&file) {
                Ok(graph) => {
                    self.graph = graph;
                    if let Some(graph_data) = self.graph_data.clone() {
                        self.graph.set_graph_data(graph_data);
                    }
                    self.graph.reload_all_include_graphs(workdir.clone());
                    self.graph.init(workdir.clone());
                    self.current_file = Some(file.to_str().unwrap().to_owned());
                    self.clear_dirty();
                }
                Err(e) => {
                    eprintln!("打开文件失败: {:?}", e);
                }
            }
        }        
    }

    fn save(&mut self) {
        if let Some(file) = self.current_file.clone() {
            let path = Path::new(&file);
            self.save_to_path(path);
        } else {
            self.save_to();
        }
    }

    fn save_to_path(&mut self, path:&Path){
        let Ok(save_data) = bincode::serialize(&self.graph) else {
            eprintln!("保存文件失败：无法序列化行为树");
            return;
        };
        std::fs::write(path, save_data).unwrap_or_else(|e|{
            eprintln!("保存文件失败: {:?}", e);
        });
    }

    fn save_to(&mut self) {
        let workdir = self.app_config.workdir.clone().unwrap_or_default();
        let file_dialog = FileDialog::new().set_directory(workdir.clone()).add_filter("行为树", &[PROJ_EXTENSION]);
        if let Some(file) = file_dialog.save_file() {
            self.save_to_path(&file);
        }
    }

    fn import_graph(&mut self) {
        let workdir = self.app_config.workdir.clone().unwrap_or_default();
        if workdir.trim().is_empty() {
            eprintln!("导入行为树失败：workdir 为空");
            return;
        }
        let file_dialog = FileDialog::new().set_directory(workdir.clone()).add_filter("行为树", &[PROJ_EXTENSION]);
        if let Some(file) = file_dialog.pick_file() {
            if !file.starts_with(&workdir) {
                eprintln!("导入行为树失败：文件不在工作目录中");
                return;
            }

            if let Some(diff_path) = pathdiff::diff_paths(&file, &workdir) {
                let normalize_path = diff_path.normalize();
                let Some(diff_path) = normalize_path.to_str() else {
                    eprintln!("导入行为树失败：无法获取相对路径");
                    return;
                };
                self.graph.add_include_graph(diff_path.to_owned(), workdir);
            }
        }
    }

    fn remove_include_graph(&mut self, name: &str) {
        self.graph.remove_include_graph(name, self.app_config.workdir.clone().unwrap_or_default());
    }

    fn export(&self){
        let Some(ref currnet_file) = self.current_file else {
            self.export_to();
            return;
        };
        
        if currnet_file.is_empty() {
            self.export_to();
            return;
        }

        if let Some(file_stem) = Path::new(currnet_file).file_stem() {
            if let Some(file_stem) = file_stem.to_str() {
                let export_dir = self.app_config.export_dir.clone().unwrap_or_default();
                let export_file = Path::new(&export_dir).join(format!("{}.{}", file_stem, "json"));
                let Ok(export_data) = generate_export_graph_data(&self.graph, self.app_config.workdir.clone().unwrap_or_default()) else {
                    eprintln!("导出文件失败：无法生成导出数据");
                    return;
                };
                let Ok(export_data) = serde_json::to_string(&export_data) else {
                    eprintln!("导出文件失败：无法序列化导出数据");
                    return;
                };

                std::fs::write(&export_file, export_data).unwrap_or_else(|e|{
                    eprintln!("导出文件失败: {:?}", e);
                });
            }            
        }
    }

    fn export_to(&self){
        let export_dir = self.app_config.export_dir.clone().unwrap_or_default();
        let file_dialog = FileDialog::new().set_directory(export_dir.clone()).add_filter("行为树", &["json"]);
        if let Some(file) = file_dialog.save_file() {
            let Ok(export_data) = generate_export_graph_data(&self.graph, self.app_config.workdir.clone().unwrap_or_default()) else {
                eprintln!("导出文件失败：无法生成导出数据");
                return;
            };
            let Ok(export_data) = serde_json::to_string(&export_data) else {
                eprintln!("导出文件失败：无法序列化导出数据");
                return;
            };

            std::fs::write(&file, export_data).unwrap_or_else(|e|{
                eprintln!("导出文件失败: {:?}", e);
            });
        }
    }
}
